﻿.model tiny

.code
org 100h

.286
locals

Start:		
		mov ax, offset s_Vasya  ;
		push ax                 ;
		mov ax, 1               ;
		push ax                 ;
		mov ax, offset s_format ;
		push ax                 ;
		
		call printf             ; printf ("Hello, my %dst friend, %s", 1, "Vasya"); 
		add sp, 6               ;
Stop:
     		mov ax, 4c00h           ;
     		int 21h                 ;
     		
s_format:     	db 'Hello, my %dst friend, %s Pupkin!', 0, '$'
s_Vasya:        db 'Vasya', 0, '$'	

;===============================================================================;
; This proc puts AX as a binary number.                                                                               
; Entry:	sp[+0] -> format string
;               sp[+2n] = arguments.
; Exit:		AX = 0ffffh for bad '%'.                                                                             
; Destr:	AX, BX, CX, DX, SI, (ES for %x).                                                                             
;===============================================================================;

printf          proc                    ;

                push bp                 ;
                mov bp, sp              ;
                
                mov si, [bp+4]          ;
                mov bx, bp              ;
                add bx, 4               ;
                
@@Iter:         lodsb                   ; Загружаем символ si в al.
                or al, al               ;
                jz @@Stop               ; Дошли до конца форматной строки - выходим.
                
                cmp al, '%'             ;
                je @@Service            ; '%' => служебный символ.
                
                mov dl, al              ;
                call Putc               ; Если не '%' и не 0 - печатаем символ.               
                jmp @@Iter              ;
                
;--------------|'%' switch block. |---------------------------------------------;                
                
@@Service:      lodsb                   ; switch al {
                add bx, 2               ; we get next argument.
                
                cmp al, 's'             ; case 's': put_string.
                je @@p_string           ; 
                cmp al, 'c'             ; case 'c': put_char.
                je @@p_char             ;
                cmp al, 'b'             ; case 'b': put_binary.
                je @@p_binary           ;
                cmp al, 'd'             ; case 'd': put_decimal.
                je @@p_decimal          ;
                cmp al, 'x'             ; case 'x': put_hexadronal.
                je @@p_hexadronal       ;
                jne @@Fail              ; default: goto Fail.
                ;|end of switch block.| ; }
                
@@p_string:     push si                 ; si нам нужен.
                mov si, [bx]            ;
                call Puts               ; Берет строку в si, выводит ее. Портит ax, si и dx.
                pop si                  ; 
                jmp @@Iter              ;
                
@@p_char:       mov dl, [bx]            ;
                call Putc               ; Берет чарик из dl, выводит его. Портит ah и dl.
                jmp @@Iter              ;
                
@@p_binary:     mov ax, [bx]            ;
                push bx                 ; bx нам нужен.
                call Putb               ;
                pop bx                  ;
                jmp @@Iter              ; Берет ax, выводит его как b. Портит ax, bx, cx, dx.
                
@@p_decimal:    mov ax, [bx]            ;
                push bx                 ; bx нам нужен.
                call Putd               ;
                pop bx                  ;
                jmp @@Iter              ; Берет ax, выводит его как d. Портит ax, bx, cx, dx.
                
@@p_hexadronal: mov ax, [bx]            ;
                push bx                 ; bx нам нужен.
                call Puth               ;
                pop bx                  ;
                jmp @@Iter              ; Берет ax, выводит его как h. Портит ax, bx, cx, dx, es.

@@Stop:         xor ax, ax              ;
                jmp @@Exit              ;
                
@@Fail:         mov ax, 0ffffh          ;
                jmp @@Exit              ;
                
@@Exit:         pop bp                  ;
                ret                     ;
                endp                    ;

;===============================================================================;
; This proc puts string from si.                                                                               
; Entry:	SI -> string.
; Exit:		None.
; Destr:	AX, DX.                                                                              
;===============================================================================;

Puts            proc                    ;
                
                mov ah, 09h             ;
                mov dx, si              ;
                int 21h                 ;
                
                mov ah, 02h             ;
                mov dl, 08h             ;
                int 21h                 ;

                ret                     ;
                endp                    ;

;===============================================================================;
; This proc puts char from dl.                                                                               
; Entry:	DL = char.
; Exit:		None.
; Destr:	AX.                                                                              
;===============================================================================;

Putc            proc                    ;
                
                mov ah, 02h             ;
                int 21h                 ;

                ret                     ;
                endp                    ;
                
;===============================================================================;
; This proc puts AX as a binary number.                                                                               
; Entry:	AX = number to put.
; Exit:		AX = number of symbols printed.                                                                              
; Destr:	AX, BX, CX, DX                                                                              
;===============================================================================;
                                	
Putb		proc	        	; 
                                	
		mov bx, ax		; my number
		mov ax, 02h		;
		;mov dh, 01h		; SAY we don't need any nills yet.
		mov cx, 10h 		;
@@Next:				
		rol bx, 1		; 
                mov dl, bl		;    
		and dl, 01h		;
		                
		;cmp dl, dh		;
		;jb @@Continue		; if you don't need nill, but get it - GO AWAY.
                
		;xor dh, dh		; SAY nills become useful since now.      
		add dl, '0'		;      				
		int 21h			; Outputs first bit.
@@Continue:	loop @@Next		; for (cl = 16, cl > 0; cl--)
                
		;mov dl, 'b'		;
		;int 21h		;	
                
		ret			; 
		endp            	;

;===============================================================================;
; This proc puts AX as a hexadronal number.                                                                               
; Entry:	AX = number to put.
; Exit:		None                                                                              
; Destr:	AX, BX, CX, DX, ES                                                                              
;===============================================================================;

Puth		proc			;

		mov es, ax		; my number
		;mov dh, 01h		; SAY we don't need any nills yet.
		xor dh, dh              ;
		mov cx, 04h		;
@@Next:
		mov bx, offset Table_   ;
		mov ax, es              ;
		rol ax, 4		;                 
		mov es, ax		;
                mov dl, al		;
                and dl, 0fh		;

                ;cmp dl, dh		;
                ;jb @@Continue		; if you don't need nill, but get it - GO AWAY.

                ;xor dh, dh		; SAY nills become useful since now.
                add bx, dx		; we know already, that dh == 0. 	
                mov dl, [bx]		; 
                mov ah, 02h		;
                int 21h			; Outputs first half of byte. 
@@Continue:     loop @@Next            ; for (cl = 4, cl > 0, cl--)

		;mov ah, 02h		;
		;mov dl, 'h'		;
		;int 21h			;

		ret			;
		endp			;
                                         
Table_:		db '0123456789abcdef'   ;

;===============================================================================;
; This proc puts AX as a decimal number.                                                                               
; Entry:	AX = number to put.
; Exit:		AX = number of symbols printed.                                                                              
; Destr:	AX, BX, CX, DX                                                                             
;===============================================================================;

Putd		proc			;

		xor cx, cx		;

@@Push:         xor dx, dx		; dx = 0
		mov bx, 0ah		; bx = 10d
                div bx                  ;                         
                push dx			;
                inc cx			;

                test ax, ax		;
                je @@Break		;
                
		cmp cx, 05h             ;
		jb @@Push		; for (cl = 0; cl < 5; cl++)

@@Break:	mov ah, 02h		;
		mov bl, 01h		; SAY we don't need any nills yet.

@@Next: 	pop dx			;

		cmp dl, bl		;
		jb @@Continue		; if you don't need nill, but get it - GO AWAY.

		xor bl, bl 		; SAY nills become useful since now.
		add dl, '0'		;
		int 21h			; Outputs first digit.
@@Continue:	loop @@Next 		; for (; cl > 0; cl--)

		;mov ah, 02h		;
		;mov dl, 'd'		;
		;int 21h		;

		ret			;
		endp			;

;===============================================================================;
; This proc gets a binary number in AX.                                                                               
; Entry:	None
; Exit:		AX = number got.                                                                               
; Destr:	AX, BX                                                                             
;===============================================================================;

Getb		proc			;
		
		xor bx, bx		;
@@Getmore:	mov ah, 01h		;
		int 21h

		cmp al, 'b'		;
		je @@Stop

		sub al, '0'		;
		shl bx, 01h		;
		add bl, al		; bx = 2*bx + al

		jmp @@Getmore		;

@@Stop:         mov ax, bx		;
		ret			;
		endp			;

;===============================================================================;
; This proc gets a hexadronal number in AX.                                                                               
; Entry:	None
; Exit:		AX = number got.                                                                               
; Destr:	AX, BX                                                                             
;===============================================================================;

Geth		proc			;

		xor bx, bx		;
@@Getmore:	mov ah, 01h		;
		int 21h			;

		cmp al, 'h'		;
		je @@Stop		;

		shl bx, 04h		;
		cmp al, '9'		;
		ja @@Got_letter 	;
		sub al, '0'		;
		jmp @@Iter		;

@@Got_letter:	cmp al, 'F'		;
		ja @@Got_small		;
@@Got_CAPITAL:	sub al, 'A' - 0ah	;
		jmp @@Iter 		;

@@Got_small:	sub al, 'a' - 0ah	;

@@Iter:	        add bl, al		;
		jmp @@Getmore		;

@@Stop:	        mov ax, bx		;
		ret			;
		endp			;

;===============================================================================;
; This proc gets a decimal number in AX.                                                                               
; Entry:	None
; Exit:		AX = number got.                                                                               
; Destr:	AX, BX, CX                                                                             
;===============================================================================;

Getd		proc			;

                xor bx, bx		;
@@Getmore:	mov ah, 01h             ;
		int 21h                 ;

		cmp al, 'd'		;
		je @@Stop		;
		mov cl, al		;

		mov ax, bx		;
		mov bx, 0ah		;
		mul bx			;
		mov bx, ax		; bx*= 10

		sub cl, '0'		;
		xor ch, ch		;
		add bx, cx		;
		jmp @@Getmore		;

@@Stop:	        mov ax, bx		;
		ret			;
		endp			;

;===============================================================================;

end		Start           	;

